#include "TaskWrapper.h"

TaskWrapper::TaskWrapper(QObject *parent)
    : QObject{parent}, hasTaskRunning(false)
{
    ScanApiResult::RemoteScanApiResult initRes = taskInitScanModule();
    if (initRes.code != 200){
        qCritical() << "System Scan Part Loss, Check";
        // QCoreApplication::exit(0);
    }

    sqlPtr = AnalysisSql::instance();
    runPtr = nullptr;
}

ScanApiResult::RemoteScanApiResult TaskWrapper::taskInitScanModule(){
    try{
        return SyncScanApi::initScanPath();
    }catch(const std::exception &e){
        qCritical() << "An error in init scan module" << e.what();
        return {-1, e.what()};
    }
}


void TaskWrapper::exampleLoop(){
    qDebug() << "i was called";
}


void TaskWrapper::nextTaskStart(){
    // 1. 判断当前是否正在执行流程，如果正在执行，周期函数弹出
    if(hasTaskRunning) {
        qDebug() << "A task is running" << Qt::endl;
        return ;
    }else{
        // 2. 否则设置状态值为正在执行
        hasTaskRunning = true;
    }

    try{
        _nextTaskStart();
    }catch(const std::exception &e){
        qCritical() << "task loop failed, check " << e.what();
        hasTaskRunning = false;
    }
}

void TaskWrapper::_nextTaskStart(){
    // 3. 使用ScanApi获取下一个需要执行的对象
    ScanApiResult::RemoteScanApiCacheResult fileCache = taskGetNextFileObj();
    if(fileCache.code == -1){ qDebug() << "Remote Cache cleaned" << Qt::endl; hasTaskRunning = false; return ;}
    else if(fileCache.code != 200) throw std::runtime_error(fileCache.errMsg.toStdString());

    // 4. 写入需要执行的对象信息到数据库
    // 20240115152851-test115-right-center-1998.12-20240115152917_s
    QStringList splitList = fileCache.fileName.split("-");
    QString patientDatabaseId = splitList[0];  // 检测编号
    QString patientName = splitList[1]; // 病人名称

    // 写入局部缓存
    nowFile = fileCache;
    nowSql = sqlPtr->createPatient(patientName, patientDatabaseId, fileCache.fileName);

    if (nowSql.id == -1) throw std::runtime_error("create sql task failed, check log");

    // 5. 使用AsyncRunner创建需要执行计算的线程对象
    const QString runningOptions = TaskApi::DEFAULT_RUNNING_OPTIONS;  // 运行时参数
    QString absFilePath = QDir(ScanRemoteApi::scanPath).filePath(fileCache.fileName);
    QVector<QString> f{absFilePath};
    runPtr = new AsyncRunner(patientName, patientDatabaseId, f,  runningOptions);

    QObject::connect(runPtr, &AsyncRunner::AsyncDone, this, &TaskWrapper::AsyncRunningDone);
    runPtr->start();

}

void TaskWrapper::AsyncRunningDone(const AsyncRunnerResult res){
    // simple debug
    qDebug() << "runner result" << Qt::endl
             << "\t status" << res.taskStatus << Qt::endl
             << "\t taskId" << res.taskId << Qt::endl
             << "\t taskOp"  << res.options << Qt::endl
             << "\t ok" << res.okRes << Qt::endl
             << "\t fail" << res.errMsg << Qt::endl;

    // 6. 消费远程文件
    bool remoteOk = true;
    if (res.taskStatus == ResultEnum::SUCCESS){
        ScanApiResult::RemoteScanApiResult consumeRes = taskConsumeFileObj();
        if (consumeRes.code != 200) {
            // 立即释放
            remoteOk = false;
            qCritical() << "Remote Scan Module loss" << Qt::endl;
        }
    }

    // 7. 释放状态
    hasTaskRunning = false;

    // 8. 执行完成后写入状态到数据库
    bool updateRes = sqlPtr->updateTaskStatus(nowSql.id, res.taskId, res.options, res.taskStatus, res.errMsg);
    if(!updateRes){
        qCritical() << "Qt update sql error" << Qt::endl
                    << "\t sql id: " << nowSql.id;
    }

    // 释放变量
    delete runPtr;
    runPtr = nullptr;

    // 9. 触发完成信号，ui触发相关更新逻辑
    emit taskRunningDone(nowFile.fileName, res.errMsg);  // 如果需要更多参数自己定义
}

ScanApiResult::RemoteScanApiCacheResult TaskWrapper::taskGetNextFileObj(){
    try{
        return SyncScanApi::getNextCache();
    }catch(const std::exception &e){
        qCritical() << "An error in get next cache" << e.what();
        return {-1, e.what(), "", 0};
    }
}

ScanApiResult::RemoteScanApiResult TaskWrapper::taskConsumeFileObj(){
    try{
        return SyncScanApi::consumeFileCache(nowFile.id);
    }catch(const std::exception &e){
        qCritical() << "An error in consume file" << e.what();
        return {-1, e.what()};
    }
}

